LÄs upp kraften i useRef i React. Utforska olika anvÀndningsfall, inklusive direkt DOM-Ätkomst, hantering av muterbara vÀrden och optimering av funktionella komponenter.
React useRef: BemÀstra mönster för lagring av muterbara vÀrden
useRef Àr en kraftfull hook i React som erbjuder ett sÀtt att bevara vÀrden mellan renderingar utan att orsaka omrenderingar nÀr dessa vÀrden Àndras. Den förknippas ofta med direkt Ätkomst till DOM-element, men dess kapacitet strÀcker sig lÄngt bortom det. Denna omfattande guide kommer att fördjupa sig i de olika anvÀndningsfallen för useRef, vilket ger dig möjlighet att skriva mer effektiv och underhÄllbar React-kod.
FörstÄ useRef: Mer Àn bara DOM-Ätkomst
I grunden returnerar useRef ett muterbart ref-objekt vars .current-egenskap initieras med det angivna argumentet (initialValue). Det returnerade objektet kommer att bestÄ under hela komponentens livscykel. Avgörande Àr att en Àndring av .current-egenskapen inte utlöser en omrendering. Detta Àr den viktigaste skillnaden mellan useRef och useState.
Ăven om Ă„tkomst till DOM-element Ă€r ett vanligt anvĂ€ndningsfall, utmĂ€rker sig useRef för att hantera alla muterbara vĂ€rden som inte behöver orsaka en omrendering nĂ€r de uppdateras. Detta gör den ovĂ€rderlig för uppgifter som:
- Lagra tidigare vÀrden frÄn props eller state.
- UnderhÄlla rÀknare eller timers.
- SpÄra fokustillstÄnd utan att orsaka omrenderingar.
- Lagra alla muterbara vÀrden som behöver bestÄ över renderingar.
GrundlÀggande anvÀndning: à tkomst till DOM-element
Det mest kÀnda anvÀndningsfallet Àr att komma Ät DOM-element direkt. Detta Àr anvÀndbart för scenarier dÀr du behöver interagera imperativt med en DOM-nod, som att fokusera ett inmatningsfÀlt, mÀta dess dimensioner eller utlösa animationer.
Exempel: Fokusera ett inmatningsfÀlt
HÀr Àr hur du kan anvÀnda useRef för att fokusera ett inmatningsfÀlt nÀr en komponent monteras:
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Fokusera inmatningsfÀltet vid montering
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Tom beroendearray sÀkerstÀller att detta körs endast en gÄng vid montering
return (
<input type="text" ref={inputRef} placeholder="Skriv in text" />
);
}
export default MyComponent;
Förklaring:
- Vi skapar en ref med
useRef(null). InitialvÀrdet Àrnulleftersom inmatningselementet inte existerar Àn nÀr komponenten renderas första gÄngen. - Vi kopplar ref:en till inmatningselementet med
ref-propen:ref={inputRef}. React kommer automatiskt att sÀttainputRef.currenttill DOM-noden nÀr inmatningselementet monteras. - Vi anvÀnder
useEffectmed en tom beroendearray ([]) för att sÀkerstÀlla att effekten körs endast en gÄng efter att komponenten har monterats. - Inuti effekten kontrollerar vi om
inputRef.currentexisterar (för att undvika fel om elementet inte Àr tillgÀngligt Àn) och anropar sedaninputRef.current.focus()för att fokusera inmatningsfÀltet.
Bortom DOM-Ätkomst: Hantera muterbara vÀrden
Den verkliga kraften hos useRef ligger i dess förmÄga att lagra muterbara vÀrden som bestÄr över renderingar utan att utlösa omrenderingar. Detta öppnar upp ett brett spektrum av möjligheter för att optimera komponentbeteende och hantera tillstÄnd i funktionella komponenter.
Exempel: Lagra tidigare vÀrden frÄn props eller state
Ibland behöver du komma Ät det tidigare vÀrdet av en prop eller en state-variabel. useRef erbjuder ett rent sÀtt att göra detta utan att utlösa onödiga omrenderingar.
import React, { useRef, useEffect } from 'react';
function MyComponent({ value }) {
const previousValue = useRef(value);
useEffect(() => {
// Uppdatera ref:ens .current-egenskap med det nuvarande vÀrdet
previousValue.current = value;
}, [value]); // Effekten körs nÀr 'value'-propen Àndras
// Nu kan du komma Ät det tidigare vÀrdet med previousValue.current
return (
<div>
Nuvarande vÀrde: {value}
<br />
FöregÄende vÀrde: {previousValue.current}
</div>
);
}
export default MyComponent;
Förklaring:
- Vi initierar ref:en
previousValuemed det initiala vÀrdet frÄnvalue-propen. - Vi anvÀnder
useEffectför att uppdaterapreviousValue.current-egenskapen nÀrhelstvalue-propen Àndras. - Inuti komponenten kan vi nu komma Ät det tidigare vÀrdet av
value-propen med hjÀlp avpreviousValue.current.
AnvÀndningsfallsexempel: SpÄra Àndringar i API-svar (Internationellt scenario)
FörestÀll dig att du bygger en instrumentpanel som visar vÀxelkurser hÀmtade frÄn ett API. API:et kan returnera kurserna i olika format eller med varierande precision beroende pÄ datakÀllan (t.ex. ett API frÄn Europeiska centralbanken jÀmfört med ett API frÄn en sydostasiatisk finansiell institution). Du kan anvÀnda useRef för att spÄra den tidigare vÀxelkursen och visa en visuell indikator (t.ex. en grön pil upp eller en röd pil ner) för att visa om kursen har ökat eller minskat sedan den senaste uppdateringen. Detta Àr avgörande för internationella anvÀndare som förlitar sig pÄ dessa kurser för finansiella beslut.
Exempel: UnderhÄlla rÀknare eller timers
useRef Àr perfekt för att hantera rÀknare eller timers som inte behöver utlösa omrenderingar. Du kan till exempel anvÀnda den för att spÄra antalet gÄnger en knapp har klickats eller för att implementera en enkel timer.
import React, { useRef, useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const clickCount = useRef(0); // Initiera ref:en med 0
const handleClick = () => {
clickCount.current++; // Ăka ref:ens .current-egenskap
setCount(clickCount.current); //Ăka state vilket orsakar omrendering.
};
return (
<div>
<p>Knappen klickad: {count} gÄnger</p>
<button onClick={handleClick}>Klicka hÀr</button>
</div>
);
}
export default MyComponent;
Förklaring:
- Vi initierar en ref
clickCountmed vÀrdet 0. - I
handleClick-funktionen ökar viclickCount.current-egenskapen. Detta utlöser inte en omrendering. - Vi uppdaterar Àven state-variabeln 'count' vilket utlöser en omrendering.
Exempel: Implementera en Debounce-funktion
Debouncing Àr en teknik som anvÀnds för att begrÀnsa hur ofta en funktion exekveras. Den anvÀnds ofta i sökfÀlt för att förhindra överdrivna API-anrop medan anvÀndaren skriver. useRef kan anvÀndas för att lagra det timer-ID som anvÀnds i debounce-funktionen.
import React, { useState, useRef, useEffect } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const timerRef = useRef(null); // Spara timer-ID:t
const handleChange = (event) => {
const newSearchTerm = event.target.value;
setSearchTerm(newSearchTerm);
// Rensa den föregÄende timern om den finns
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// SĂ€tt en ny timer
timerRef.current = setTimeout(() => {
// Simulera ett API-anrop
fetch(`https://api.example.com/search?q=${newSearchTerm}`)
.then(response => response.json())
.then(data => setResults(data.results));
}, 300); // Debounce i 300 millisekunder
};
return (
<div>
<input
type="text"
placeholder="Sök..."
value={searchTerm}
onChange={handleChange}
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
export default MyComponent;
Förklaring:
- Vi anvÀnder
useRefför att lagra timer-ID:t itimerRef. - I
handleChange-funktionen rensar vi den föregÄende timern (om den finns) medclearTimeout(timerRef.current). - Vi sÀtter sedan en ny timer med
setTimeoutoch lagrar timer-ID:t itimerRef.current. - API-anropet görs endast efter att anvÀndaren har slutat skriva i 300 millisekunder.
HĂ€nsyn till internationalisering: NĂ€r du implementerar debouncing med API-anrop som involverar visning av information pĂ„ olika sprĂ„k, se till att ditt API stöder internationalisering och returnerar data pĂ„ anvĂ€ndarens föredragna sprĂ„k. ĂvervĂ€g att anvĂ€nda Accept-Language-headern i dina API-förfrĂ„gningar.
Exempel: SpÄra fokustillstÄnd utan omrenderingar
Du kan anvÀnda useRef för att spÄra om ett element har fokus utan att orsaka omrenderingar. Detta kan vara anvÀndbart för att styla element baserat pÄ deras fokustillstÄnd eller för att implementera anpassad logik för fokushantering.
import React, { useRef, useState } from 'react';
function MyComponent() {
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef(null);
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
return (
<div>
<input
type="text"
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<p>FÀltet Àr fokuserat: {isFocused ? 'Ja' : 'Nej'}</p>
</div>
);
}
export default MyComponent;
useRef vs. useState: VÀlja rÀtt verktyg
Det Àr viktigt att förstÄ de viktigaste skillnaderna mellan useRef och useState för att kunna vÀlja rÀtt verktyg för uppgiften.
| Egenskap | useRef | useState |
|---|---|---|
| Utlöser omrendering | Nej | Ja |
| Syfte | Lagra muterbara vÀrden som inte behöver utlösa omrenderingar. à tkomst till DOM-element. | Hantera state som behöver utlösa omrenderingar. |
| BestÀndighet | BestÄr över omrenderingar. | BestÄr över omrenderingar, men vÀrdet uppdateras med hjÀlp av setter-funktionen. |
BĂ€sta praxis och vanliga fallgropar
- Mutera inte state direkt: Ăven om
useReflÄter dig mutera vÀrden direkt, undvik att direkt mutera state-variabler som hanteras avuseState. AnvÀnd alltid setter-funktionen frÄnuseStateför att uppdatera state. - Var medveten om sidoeffekter: NÀr du anvÀnder
useRefför att hantera vÀrden som pÄverkar UI:t, var medveten om potentiella sidoeffekter. Se till att din kod beter sig förutsÀgbart och inte introducerar ovÀntade buggar. - Förlita dig inte pÄ
useRefför renderingslogik: Eftersom Ă€ndringar iuseRefinte utlöser omrenderingar, förlita dig inte pĂ„ dess vĂ€rden direkt för att bestĂ€mma vad som ska renderas. AnvĂ€nduseStateför vĂ€rden som behöver styra renderingslogiken. - TĂ€nk pĂ„ prestandakonsekvenser: Ăven om
useRefkan hjÀlpa till att optimera prestanda genom att förhindra onödiga omrenderingar, var medveten om att överdriven anvÀndning av muterbara vÀrden kan göra din kod svÄrare att förstÄ och felsöka.
Avancerade anvÀndningsfall och mönster
Bevara vÀrden över komponentinstanser
Medan `useRef` bevarar vÀrden över renderingar av en *enda* komponentinstans, behöver du ibland ett vÀrde som bestÄr över *olika* instanser av samma komponent. Detta krÀver ett nÄgot annorlunda tillvÀgagÄngssÀtt, ofta genom att utnyttja en variabel pÄ modulnivÄ i kombination med `useRef`.
// myComponent.js
let globalCounter = 0; // Variabel pÄ modulnivÄ
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const counterRef = useRef(globalCounter); // Initiera med det globala vÀrdet
useEffect(() => {
// Uppdatera den globala rÀknaren nÀr ref:en Àndras
globalCounter = counterRef.current;
}, [counterRef.current]);
const increment = () => {
counterRef.current++;
//Ingen setState behövs, sÄ ingen omrendering
};
return (
<div>
<p>RĂ€knare: {counterRef.current}</p>
<button onClick={increment}>Ăka</button>
</div>
);
}
export default MyComponent;
Viktiga övervĂ€ganden: Detta mönster introducerar en global variabel, sĂ„ var extremt försiktig med potentiella sidoeffekter och race conditions, sĂ€rskilt i komplexa applikationer. ĂvervĂ€g alternativa tillvĂ€gagĂ„ngssĂ€tt som att anvĂ€nda en context provider om vĂ€rdet behöver delas mellan flera komponenter pĂ„ ett mer kontrollerat sĂ€tt.
Slutsats: SlÀpp lös kraften i useRef
useRef Àr ett mÄngsidigt verktyg i React som strÀcker sig lÄngt bortom att bara komma Ät DOM-element. Genom att förstÄ dess förmÄga att lagra muterbara vÀrden utan att utlösa omrenderingar kan du optimera dina komponenter, hantera state mer effektivt och bygga mer högpresterande och underhÄllbara React-applikationer. Kom ihÄg att anvÀnda det omdömesgillt och alltid övervÀga de potentiella avvÀgningarna mellan prestanda och kodens tydlighet.
Genom att bemÀstra mönstren som beskrivs i den hÀr guiden kommer du att vara vÀl rustad att utnyttja den fulla potentialen hos useRef i dina React-projekt, oavsett om du bygger en enkel webbapplikation eller ett komplext företagssystem. Kom ihÄg att ta hÀnsyn till internationalisering och tillgÀnglighet nÀr du bygger för en global publik!